﻿#region Using Statements
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using DirectZZT.Shared.Core;
using DirectZZT.Shared.Network;
using Lidgren.Network;
#endregion

namespace DirectZZT.Server
{
    /// <summary>
    /// Implements the <see cref="IServer"/> interface.
    /// </summary>
    [Export("Server", Type = typeof(IServer))]
    public sealed class Server : IServer
    {
        #region Constants

        private const string AppIdentifier = "$DIRECTZZT$";
        private const int MaxConnections = 4;
        private const int Port = 61234;

        #endregion

        #region Fields

        private NetPeerConfiguration _configuration;
        private NetServer _server;
        private IFormatter _formatter;
        private ICompression _compression;

        private List<ClientInfo> _connectedClients;

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the Server class.
        /// </summary>
        public Server()
        {
            _configuration = new NetPeerConfiguration(AppIdentifier);
            _configuration.MaximumConnections = MaxConnections;
            _configuration.Port = Port;
            // TODO: makes sense? check.
            _configuration.UseMessageRecycling = true;

            _connectedClients = new List<ClientInfo>(4);

            _formatter = new BinaryFormatter();
            _compression = new CompressionGzip();
        }

        #endregion

        #region Methods

        private void ReceivedCallback(object state)
        {
            var message = _server.ReadMessage();
            using (MemoryStream stream = new MemoryStream(message.ReadBytes(message.LengthBytes)))
            {
                ClientPacket packet = (ClientPacket)_formatter.Deserialize(stream);

                // get sender
                ClientInfo client = _connectedClients.Find(c => c.EndPoint.Address == message.SenderEndpoint.Address);
                if (client == null)
                {
                    return;
                }

                // TODO
            }
        }

        #endregion

        #region IServer Members

        /// <summary>
        /// Sends the packet to all connected clients.
        /// </summary>
        /// <param name="packet">The packet to send.</param>
        public void SendPacket(ServerPacket packet)
        {
            using (MemoryStream stream = new MemoryStream(512))
            {
                // write message
                _formatter.Serialize(stream, packet);

                // prepare and send message to all clients
                NetOutgoingMessage msg = _server.CreateMessage((int)stream.Length);
                msg.Write(_compression.Compress(stream.ToArray()));
                _server.SendToAll(msg, NetDeliveryMethod.ReliableOrdered);
            }
        }

        /// <summary>
        /// Starts the server.
        /// </summary>
        public void Start()
        {
            _server = new NetServer(_configuration);
            _server.RegisterReceivedCallback(ReceivedCallback);
            _server.Start();
        }

        /// <summary>
        /// Makes the server to process one update step.
        /// </summary>
        public void Process()
        {

        }

        /// <summary>
        /// Disconnects all clients and shuts down the server.
        /// </summary>
        public void Shutdown()
        {
            _server.Shutdown("Shutting down server.");
        }

        #endregion
    }
}
